package com.jplus.mvc.action.api.kit;

import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.jplus.core.utill.JSON;
import com.jplus.core.utill.JUtil;
import com.jplus.core.utill.StreamUtil;

public class IDCardKit {
	public static void main(String[] args) {
		System.out.println(new IDCardKit().doCheck("420582199110026254"));
		System.err.println(new IDCardKit().doBuild("110101", "19910101", false));
	}

	// 加权因子
	private int power[] = { 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2 };
	private char check[] = { '1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2' };
	private Map<String, String[]> mapArea = new HashMap<>();

	public IDCardKit() {
		try {
			InputStream is = ClassLoader.getSystemResourceAsStream("data/idcardArea.csv");
			String file = new String(StreamUtil.toByteArray(is));
			List<String> list = Arrays.asList(file.split("\n"));
			for (String str : list) {
				String[] line = str.split(",");
				if (line.length >= 3) {
					mapArea.put(line[0], new String[] { line[0].trim(), line[1].trim(), line[2].trim() });
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public void addArea(Integer areaId, String areaName, Integer pid) {
		mapArea.put(areaId.toString(), new String[] { areaId.toString(), areaName, pid.toString() });
	}

	public List<String[]> listArea() {
		return new ArrayList<>(mapArea.values());
	}

	/**
	 * 18位身份证号码 校验
	 */
	public IDCard doCheck(String card) {
		if (card == null || card.trim().equals("") || card.length() != 18)
			return new IDCard(card, STATUS.FAIL, "身份证号长度 不正常");
		String card17 = card.substring(0, 17);
		if (!JUtil.isNumber(card17))
			return new IDCard(card, STATUS.FAIL, "身份证号前17位必须为数字");
		String acode = card.substring(0, 6);
		String[] area = mapArea.get(acode);
		if (area == null)
			return new IDCard(card, STATUS.FAIL, "身份证号地区码不正确");
		String birthday = card.substring(6, 14);
		Integer birth = Integer.parseInt(birthday);
		Integer nowday = getNowDay();
		Integer age = (nowday - birth) / 10000;
		if (age <= 0 || age > 150)
			return new IDCard(card, STATUS.FAIL, "身份证号出生日期不正确");
		String sex = Integer.parseInt(card.charAt(16) + "") % 2 == 0 ? "女" : "男";
		char clast = getPowerCheck(card17);
		char olast = card.toUpperCase().charAt(17);
		if (clast != olast)
			return new IDCard(card, STATUS.FAIL, "身份证号校验位不正常");
		return new IDCard(card, card.length(), age, birthday, sex, acode, getAreaDesc(acode), STATUS.SUCC, "身份证格式正确");
	}

	/**
	 * 18位身份证号码 生成
	 */
	public IDCard doBuild(String area, String ymd, boolean sex) {
		String[] areas = mapArea.get(area);
		if (areas == null || area.length() != 6)
			return new IDCard(null, STATUS.FAIL, "身份证号地区码不正确");
		if (ymd == null || !JUtil.isNumber(ymd) || ymd.length() != 8)
			return new IDCard(null, STATUS.FAIL, "身份证号出生日期不正确");
		int rd = (int) (Math.random() * 89 + 10);
		int rdx = (int) (Math.random() * 5) * 2;
		String card17 = area + ymd + rd + (sex ? rdx + 1 : rdx);
		String card = card17 + getPowerCheck(card17);
		return doCheck(card);
	}

	private List<String[]> getAreaDesc(String acode) {
		List<String[]> list = new ArrayList<>();
		String[] area = mapArea.get(acode);
		if (area != null) {
			list.addAll(getAreaDesc(area[2]));
			list.add(area);
		}
		return list;
	}

	/**
	 * 通过前17位获取校验位18
	 */
	private char getPowerCheck(String card17) {
		char[] bit = card17.toCharArray();
		int sum = 0;
		for (int i = 0; i < bit.length; i++)
			sum += Integer.parseInt(bit[i] + "") * power[i];
		return check[sum % 11];
	}

	private Integer getNowDay() {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
		return Integer.parseInt(sdf.format(new Date()));
	}

	public enum STATUS {
		SUCC, FAIL
	}

	public class IDCard {
		public String cardNo;
		public Integer len;
		public Integer age;
		public String birthday;
		public String sex;
		public String areaCode;
		public String areaName;
		public List<String[]> area;
		public STATUS status;
		public String message;

		public IDCard(String cardNo, Integer len, Integer age, String birthday, String sex, String areaCode,
				List<String[]> area, STATUS status, String message) {
			super();
			this.cardNo = cardNo;
			this.len = len;
			this.age = age;
			this.birthday = birthday;
			this.sex = sex;
			this.status = status;
			this.message = message;
			this.areaName = "";
			for (String[] strs : area)
				this.areaName += strs[1];
			this.area = area;
			this.areaCode = areaCode;
		}

		public IDCard(String cardNo, STATUS status, String message) {
			super();
			this.cardNo = cardNo;
			this.status = status;
			this.message = message;
		}

		@Override
		public String toString() {
			return JSON.toJSONString(this);
		}

	}

}
